package com.lucker.service.rsa;



import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;



public class MyRSA {
    public static final String KEY_ALGORITHM = "RSA";
    /** 貌似默认是RSA/NONE/PKCS1Padding，未验证 */
    public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
    public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrN8d/1NwLqyQkolhItI8sR9Ts\r\n" + 
    		"I1UzKEISkDfoSBPnr+LcWlogXaivNeivwNekqfRdZagfAAOHe+rqQh3C5N0lteSJ\r\n" + 
    		"0A1homRk/TExPE4lgMiiV5T64SYlX7v/ovyOeVDZqQfp6/tzzrL/YDTQR5aURcas";
    
    public static final String PRIVATE_KEY = "MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIhPhXURgQElUCAggA\r\n" + 
    		"MBQGCCqGSIb3DQMHBAgsAtmobPTkeQSCAoC6Fvjg2gea6uD/sIBGt1W8zihYTd+e\r\n" + 
    		"lW1Tfgt9YEwwP+Qb6oBDntFnsxT1U5vDFyUhz6hW8fCYvGfSaxnJn41sMGTK8PtP\r\n" + 
    		"YTXuLVw261WQREYN7Yf/FCPA73lflD/fF/VSCTDVmyygaiJVpK/00pbPFtkfBBnW\r\n" + 
    		"9xYMZqToNL0nwkIGtT/1Eya2yCpISLBnerKJuQqVXMYDfc8k5EjgiR5c0FAMzqbe\r\n" + 
    		"QS6aIQOFqaCfgK/6QMbj64hXeRoQqnqkIOtLGe07/+74BjONewR+7AApVtCFqCQl\r\n" + 
    		"EzeGw7rWQjjVMH2OPNI8vQBoJJSrdU2T3JMmUPLKlvFdzmMweF4D3FZKRVy1EJ15\r\n" + 
    		"OZs0sZXkGb86ELHPW4ACosk+adv1WQE/yHAKED5OfhwZ+J+bUTzbO0vWqcRrOOGm\r\n" + 
    		"C3Gdoal+hGTZaNJXAdl2oYShwhUqjwzl/Lw9pQC1ZZ/yswpIRxd5PY+g53eY+T8/\r\n" + 
    		"q4hk1RSbrhjFrJNd3Z2Q2XAisRJ1sNyTdDo2cd5vxXnF/ymlOhghAT+YX9J1YOYO\r\n" + 
    		"f9AV9jhy6WBq991jTATt1A7n1dM/CMUAgktbOGadDD8RHIeIKzvf0tvom6IyTJvw\r\n" + 
    		"lZNyCH1Agw42vicImgFpUaHZOobNzpKjoo8vrxbZLHK/0IYBWD/loGitSMfg+OlS\r\n" + 
    		"wXNgpldtUd02jtG1muRZK5fiHt7qHHwGQA77AmocNnxF8NM3ykGJc0maUe779DbV\r\n" + 
    		"/M9mhaxYltINTbPtMyGZUoZMzpsbKiB9ss5MdzAxXqa48lyjfpDfq4yrCeSsMwBb\r\n" + 
    		"3APqldCjIh7+Q4EX96/tAcLcVVmKVbM3wIdme2FSq1ECHAM4Y2rfjIkQ";
    
    
    
    /** RSA密钥长度必须是64的倍数，在512~65536之间。默认是1024 */
    public static final int KEY_SIZE = 2048;

    public static final String PLAIN_TEXT = "2222222222222222222222222222222222222222222222222222234342JFDFD987GHJ9GH987GHJ9GHJG7HJ4K3HJWFRRG34342JFDFD987GHJ9GHJG7HJ4K3HJWFRRG34342JFDFD987GHJ9GHJG7HJ4K3HJWFRRG34342JFDFD987GHJ9GHJG7HJ4K3HJWFRRG34342JFDFD987GHJ9GHJG7HJ4K3HJWFRRG2222333333333333";

    public static void main(String[] args) {
        Map<String, byte[]> keyMap = generateKeyBytes();
        // 加密
        PublicKey publicKey = restorePublicKey(keyMap.get(PUBLIC_KEY));
        
        
        byte[] encodedText = RSAEncode(publicKey, PLAIN_TEXT.getBytes());
        System.out.println("RSA encoded: " + Base64.encode(encodedText));

        // 解密
        //encodedText = "EI3LAcRXySnkgQG7+MhFlLFeB9amZiUthgMr5VDzj3Ehb74QQRuzKhRzL0izOEJqbXjeG4DIp1Mda/HuFgTshjwcXBVb1fCkup5bMEkxeSJnTyDjG9MinhgWWZFUjrja6Rsq6gVp7BK4rEBCiJNi4rdBpQsxl2/LHbYD9BX++EY61T9FVF2kT+96T8innJmhpSWoBXHFGLonQoLIPwj/S89FD1IxhlY3+PoDxmJ4+r1dSMGbiG/kZX2y85gjx8MqCqj3IJogROKKfCSw1b6njBtABlliE734RgAzsESD3YYgXTTe49xECYdFeYEyOGEKC9jL9u6Ep+R7j3GiPWr7/w==".getBytes();
        PrivateKey privateKey = restorePrivateKey(keyMap.get(PRIVATE_KEY));
        System.out.println("RSA decoded: " + RSADecode(privateKey, encodedText));
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    /**
     * 生成密钥对。注意这里是生成密钥对KeyPair，再由密钥对获取公私钥
     * 
     * @return
     */
    public static Map<String, byte[]> generateKeyBytes() {

        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(KEY_SIZE);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            Map<String, byte[]> keyMap = new HashMap<String, byte[]>();
            keyMap.put(PUBLIC_KEY, publicKey.getEncoded());
            keyMap.put(PRIVATE_KEY, privateKey.getEncoded());
            return keyMap;
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 还原公钥，X509EncodedKeySpec 用于构建公钥的规范
     * 
     * @param keyBytes
     * @return
     */
    public static PublicKey restorePublicKey(byte[] keyBytes) {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);

        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec);
            return publicKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 还原私钥，PKCS8EncodedKeySpec 用于构建私钥的规范
     * 
     * @param keyBytes
     * @return
     */
    public static PrivateKey restorePrivateKey(byte[] keyBytes) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
                keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = factory
                    .generatePrivate(pkcs8EncodedKeySpec);
            return privateKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 加密，三步走。
     * 
     * @param key
     * @param plainText
     * @return
     */
    public static byte[] RSAEncode(PublicKey key, byte[] plainText) {

        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(plainText);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException
                | InvalidKeyException | IllegalBlockSizeException
                | BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 解密，三步走。
     * 
     * @param key
     * @param encodedText
     * @return
     */
    public static String RSADecode(PrivateKey key, byte[] encodedText) {

        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(encodedText));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException
                | InvalidKeyException | IllegalBlockSizeException
                | BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }
}
